messages.send: auto_verify body-echo (Phase 2 body-verify defense)#39
Merged
Conversation
Mike body-verify directive 2026-05-11 — Layer 2 SDK auto-verify
across cueapi-python. Sibling to Layer 3 force-file mode shipped in
cueapi-cli #51 + cue-mac-app commit b892613.
Bug class (caller-side shell expansion silently mutating body content
BEFORE the SDK receives it): cueapi-cli #51 closed the CLI side via
force-file mode. cueapi-python callers (notebook / script / hosted
agent runtime) hit the same class via f-strings + os.popen + format()
+ similar Python-level mutation hidden under "literal string".
Auto-verify catches it server-side via echo-back, raising
BodyVerifyMismatchError instead of silent corruption.
Changes:
cueapi/exceptions.py:
- BodyVerifyMismatchError(CueAPIError) — new exception with sent_body,
received_body, first_divergence_byte, message_id attributes.
- first_divergence_byte(a, b) — pure helper returning byte index of
first differing position. -1 when one is a proper prefix of the
other (length mismatch; caller distinguishes via len()). Cross-SDK
re-usable.
cueapi/resources/messages.py:
- send(auto_verify=True) — new kwarg, default ON per CTO concur
(Q-C4). Adds X-CueAPI-Verify-Echo: true header. After 201, checks
response.get("body_received") against sent body; raises
BodyVerifyMismatchError on mismatch.
- Backward-compat: when substrate omits body_received field (pre-
Layer-1 deploy), SDK silently no-ops. Existing callers see no
behavior change until both Layer 1 + Layer 2 are deployed.
- Opt-out: auto_verify=False omits header + skips check.
tests/test_messages_resource.py:
- 11 new tests pin:
- Default auto_verify=True adds header
- Opt-out omits header
- Byte-identical response returns normally
- Mismatched response raises BodyVerifyMismatchError with attributes
- Substrate omits echo field → no raise (backward-compat)
- Opt-out skips verify even if substrate echoes
- first_divergence_byte: equal, prefix, first-char, middle, realistic
metachar-substitution scenario
- 4 existing tests updated to expect default-on header.
- All 22 messages tests pass.
Phase 2 substrate field name `body_received` documented as locked
during joint CMA + cueapi-primary design (design Dock workspace
cue-message-silent-corruption-substrate-design-2026-05-11). If
Layer 1 ships under a different name, update _VERIFY_ECHO_FIELD
constant (single 1-line change).
CHANGELOG entry under [Unreleased].
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
mikemolinet
added a commit
that referenced
this pull request
May 11, 2026
…wire-shape) (#40) Hotfix for cueapi-python PR #39. Empirically verified 2026-05-11 ~23:17Z via direct curl probe: substrate's X-CueAPI-Verify-Echo response includes ``body_received`` as the PARSED request body (a dict with to/body/subject/priority/etc fields), NOT a flat string per the original spec wording. Before fix: SDK compared ``response["body_received"]`` (dict) against ``body`` (str) — type mismatch → ALWAYS raised BodyVerifyMismatchError on every default-auto-verify send. Regression in PR #39. After fix: SDK extracts ``body_received.body`` (str) and compares against sent body (str). Includes defensive isinstance check that falls through gracefully if a future substrate rev flattens the echo back to a string. Tests updated to use the dict shape; 1 new defensive test pins the backward-flat-string path. 23 of 23 messages tests pass. This hotfix is unblocking — every auto-verify send was broken in main until this lands. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mikemolinet
added a commit
that referenced
this pull request
May 12, 2026
…dy coverage, bump audit to 2026-05-12 (#43) Manifest was dated 2026-05-07 and missing the PR-1b event-emit endpoint coverage (4 endpoints) plus the body-verify Phase 2 + inline_body extensions that shipped 2026-05-09 → 2026-05-12. Brings the manifest back in sync with SDK head. Endpoints added to `endpoints_covered`: - POST /v1/agents/{ref}/subscriptions (subscriptions_create, PR #38; inline_body kwarg in PR #42 / cueapi #791 Item 1) - GET /v1/agents/{ref}/subscriptions (subscriptions_list, PR #38) - DELETE /v1/agents/{ref}/subscriptions/{sub_id} (subscriptions_delete, PR #38) - GET /v1/agents/{ref}/events (events_pull, PR #38) Updates to existing entries: - POST /v1/messages — added auto_verify body-verify Phase 2 (PR #39 + #40, cueapi/cueapi #795 + #798 parity) - POST /v1/cues/{id}/fire — note that #33 shipped (was "in-flight") - GET /v1/agents/roster — note that #35 shipped (was "in-flight") - GET /v1/agents/{ref}/presence — note that #35 shipped (was "in-flight") Replaced `in_flight_ports_2026_05_07` section with `ports_shipped_2026_05_08_to_2026_05_12` (now-resolved entries) plus a near-empty `ports_in_flight_2026_05_12` placeholder for future ports. Backlog row: cmp1vukmc. Out of scope: - `model_drift` section walk-through (Cue/Execution/Worker missing fields) — PR #31 just landed the Execution + Worker + Agent + Message additive models; a fuller `model_drift` refresh deserves a separate audit pass against the now-shipped models to figure out what's still drifting.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Layer 2 of the body-verify defense-in-depth (Mike directive 2026-05-11). Sibling to Layer 3 shipped in cueapi-cli #51 + cue-mac-app helpers. Closes the caller-side body-mutation bug class for Python SDK callers.
Design Dock: cue-message-silent-corruption-substrate-design-2026-05-11.
What
BodyVerifyMismatchErrornew exception incueapi.exceptionswithsent_body,received_body,first_divergence_byte,message_idattributes for programmatic recovery.first_divergence_byte(a, b)pure helper — cross-SDK reusable.MessagesResource.send(auto_verify=True)new kwarg, default ON. AddsX-CueAPI-Verify-Echo: truerequest header. SDK diffs responsebody_receivedfield against sent body + raisesBodyVerifyMismatchErroron drift. Opt-out viaauto_verify=False.Backward-compatibility
body_receivedin response): SDK silently no-ops. Existing callers see no behavior change.Test plan
Defense-in-depth status
X-CueAPI-Verify-Echoheader → responsebody_receivedecho): cueapi-primary's lane, in flight ETA 1-3d🤖 Generated with Claude Code